package com.sf.fy.uav.applet.login.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.sf.fy.uav.common.awt.JwtUtil;
import com.sf.fy.uav.applet.login.service.LoginService;
import com.sf.fy.uav.applet.utils.Aes;
import com.sf.fy.uav.common.enums.ErrorEnum;
import com.sf.fy.uav.common.enums.PlatformCodeEnum;
import com.sf.fy.uav.common.enums.ServicePrefixEnum;
import com.sf.fy.uav.common.enums.UserStatusEnum;
import com.sf.fy.uav.common.exception.BusinessException;
import com.sf.fy.uav.common.utils.PhoneEncoderUtil;
import com.sf.fy.uav.common.utils.RedisPrefixKey;
import com.sf.fy.uav.task.utils.HttpClientUtil;
import com.sf.fy.uav.user.entity.User;
import com.sf.fy.uav.user.entity.UserExtra;
import com.sf.fy.uav.user.mapper.UserExtraMapper;
import com.sf.fy.uav.user.mapper.UserMapper;
import com.sf.fy.uav.user.rest.UserRest;
import com.sf.fy.uav.user.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author LTQ
 */
@Service
public class LoginServiceImpl implements LoginService {


    private final static Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);

    //沙盒测试
    private static final String url_sandbox = "https://api.weixin.qq.com/sns/jscode2session";

    private static final Integer CONST_NUM = 0;

    @Autowired
    private IUserService iUserService;


    @Autowired
    private UserRest userRest;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${wx.appid:wxa9995496636a5ee1}")
    private String appid;

    @Value("${wx.secret:ed609905dc5a817ea3d7091a5ea90654}")
    private String secret;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserExtraMapper userExtraMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${proxy-url:sfproxy.intsit.sfcloud.local}")
    private String proxyUrl;


    @Value("${is-use-proxy:false}")
    private boolean isUseProxy;

    @Autowired
    private PhoneEncoderUtil phoneEncoderUtil;


    @Override
    public Object decipheringCode(String loginCode) {
        Map<String, String> param = new HashMap<>();
        param.put("appid", appid);
        param.put("secret", secret);
        param.put("js_code", loginCode);
        param.put("grant_type", "authorization_code");
        String body = HttpClientUtil.sendGetJsonRepeatProxy(url_sandbox, proxyUrl, 80, param, isUseProxy);
        Object object = JSONObject.parse(body);
        logger.info("微信登录解密返回结果：{}", object);
        String session_key = (String) ((JSONObject) object).get("session_key");
        if (ObjectUtils.isEmpty(session_key)) {
            throw new BusinessException(ErrorEnum.DECRYPTING_CODE_EXCEPTION);
        }
        redisTemplate.opsForValue().set(ServicePrefixEnum.RESCUE + RedisPrefixKey.WX_LOGIN_DATA + loginCode, object);
        return object;

    }

    @Override
    public String getAccessToken() {
        String accessToken = (String) redisTemplate.opsForValue().get(ServicePrefixEnum.RESCUE + RedisPrefixKey.APPLET_ACCESS_TOKEN);
        if (ObjectUtils.isEmpty(accessToken)) {
            Map<String, String> params = new HashMap<>();
            params.put("grant_type", "client_credential");
            params.put("appid", appid);
            params.put("secret", secret);
            String body = HttpClientUtil.sendGetJsonRepeatProxy("https://api.weixin.qq.com/cgi-bin/token", proxyUrl, 80, params, isUseProxy);
            JSONObject object = JSON.parseObject(body);
            accessToken = object.getString("access_token");
            /*access_token有效时长*/
            int expires_in = object.getInteger("expires_in");
            /*过期时间减去10毫秒：10毫秒是网络连接的程序运行所占用的时间*/
            redisTemplate.opsForValue().set(ServicePrefixEnum.RESCUE + RedisPrefixKey.APPLET_ACCESS_TOKEN, accessToken);
            redisTemplate.expire(ServicePrefixEnum.RESCUE + RedisPrefixKey.APPLET_ACCESS_TOKEN, expires_in - 5, TimeUnit.SECONDS);

        }
        return accessToken;
    }

    @Override
    public String loginByWechat(String loginCode, String encryptedData, String iv) {
        Object object;
        object = redisTemplate.opsForValue().get(ServicePrefixEnum.RESCUE + RedisPrefixKey.WX_LOGIN_DATA + loginCode);
        if (ObjectUtils.isEmpty(object)) {
            object = this.decipheringCode(loginCode);
        }
        String sessionKey = (String) ((JSONObject) object).get("session_key");
        if (ObjectUtils.isEmpty(sessionKey)) {
            throw new BusinessException(ErrorEnum.DECRYPTING_CODE_EXCEPTION);
        }
        String data = null;
        try {
            data = Aes.decrypt(encryptedData, sessionKey, iv);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = JSONObject.parseObject(data);
        String phoneNumber = (String) jsonObject.get("phoneNumber");
        String countryCode = (String) jsonObject.get("countryCode");
        String openid = ((JSONObject) object).getString("openid");
        return this.managerUserAndGetToken(phoneNumber, countryCode, openid);
    }

    @Override
    public String loginByPhoneNumber(String phone, String loginCode) {
        Object object;
        object = redisTemplate.opsForValue().get(ServicePrefixEnum.RESCUE + RedisPrefixKey.WX_LOGIN_DATA + loginCode);
        if (ObjectUtils.isEmpty(object)) {
            object = this.decipheringCode(loginCode);
        }
        String openid = (String) ((JSONObject) object).get("openid");
        return this.managerUserAndGetToken(phone, "86", openid);
    }

    public String managerUserAndGetToken(String phoneNumber, String countryCode, String openid) {
        Date date = new Date();
        phoneNumber = phoneEncoderUtil.encryptString(phoneNumber);
        User user = userRest.getOne(phoneNumber, countryCode, PlatformCodeEnum.FY_RESCUE.getCode());
        if (ObjectUtils.isEmpty(user)) {
            user = new User();
            user.setPhoneNumber(phoneNumber);
            user.setCountryCode(countryCode);
            user.setCreateTime(date);
            user.setStatus(UserStatusEnum.NORMAL.getValue());
            user.setPlatformCode(PlatformCodeEnum.FY_RESCUE.getCode());
            user.setUpdateTime(date);
            userMapper.insert(user);
            UserExtra userExtra = new UserExtra();
            userExtra.setCreateTime(date);
            userExtra.setUpdateTime(date);
            userExtra.setUserId(user.getId());
            userExtra.setLastLoginTime(date);
            userExtraMapper.insert(userExtra);
        } else {
            UserExtra userExtra = userExtraMapper.selectOne(new QueryWrapper<UserExtra>().eq("user_id", user.getId()));
            if (ObjectUtils.isEmpty(userExtra)) {
                userExtra = new UserExtra();
                userExtra.setCreateTime(date);
                userExtra.setUpdateTime(date);
                userExtra.setUserId(user.getId());
                userExtra.setLastLoginTime(date);
                userExtraMapper.insert(userExtra);
            } else {
                userExtra.setLastLoginTime(date);
                userExtra.setUpdateTime(date);
                userExtraMapper.updateById(userExtra);
            }
        }
        String userId = user.getId();
        redisTemplate.opsForValue().set(ServicePrefixEnum.RESCUE + RedisPrefixKey.APPLET_OPENID + userId, openid);
        //准备存放在IWT中的自定义数据
        Map<String, Object> info = new HashMap<>(2);
        info.put("phone_number", phoneNumber);
        info.put("country_code", countryCode);
        //生成JWT字符串
        String token = JwtUtil.sign(userId, info);
        logger.info("### 登录成功, token={} ###", token);
        return token;
    }
}
